{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "2.1 第一步：前向传播（做菜过程）"
      ],
      "metadata": {
        "id": "DT4yjCHnpDJF"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import numpy as np\n",
        "\n",
        "# 初始化参数（随机配方）\n",
        "W = np.array([[0.5], [-0.3]])  # 权重（盐和酱油的用量系数）\n",
        "b = np.array([0.1])       # 偏置（基础味道）\n",
        "\n",
        "# 前向传播函数（做菜流程）\n",
        "def forward(x):\n",
        "  z = np.dot(x, W) + b    # 加权混合\n",
        "  a = 1 / (1 + np.exp(-z))  # 激活函数（味道标准化）\n",
        "  return a\n",
        "\n",
        "# 输入数据（食材）\n",
        "x = np.array([[1, 2]])  # 1份盐，2份酱油\n",
        "print(\"预测结果:\", forward(x))  # 输出：[[0.475]]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8r5OITGApEW9",
        "outputId": "17115b49-8101-4648-e9a4-9d8e3ccc07fb"
      },
      "execution_count": 55,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "预测结果: [[0.5]]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "2.2 第二步：计算损失（品尝评价）"
      ],
      "metadata": {
        "id": "HpJZAzAOpIf7"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "def loss(y_pred, y_true):\n",
        "  return (y_pred - y_true)**2  # 平方误差\n",
        "\n",
        "y_true = 0.8\n",
        "print(\"当前损失:\", loss(forward(x), y_true))  # 输出：0.105"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lWqfjKLGpK6M",
        "outputId": "e011b345-f18c-4e0a-98d9-df21de450a42"
      },
      "execution_count": 56,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "当前损失: [[0.09]]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "\n",
        "2.3 第三步：反向传播（反思调整）"
      ],
      "metadata": {
        "id": "7-O0-ow-pNWs"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "def backward(x, y_true, W, b, learning_rate=0.1):\n",
        "  # 前向传播\n",
        "  z = np.dot(x, W) + b\n",
        "  a = 1 / (1 + np.exp(-z))\n",
        "\n",
        "  # 计算梯度\n",
        "  dL_da = 2 * (a - y_true)  # 损失对输出的梯度\n",
        "  da_dz = a * (1 - a)    # sigmoid导数\n",
        "  dz_dW = x.T          # 加权和对权重的梯度\n",
        "\n",
        "  # 组合梯度\n",
        "  dL_dz = dL_da * da_dz\n",
        "  dL_dW = np.dot(dz_dW, dL_dz)\n",
        "  dL_db = dL_dz\n",
        "\n",
        "  # 更新参数\n",
        "  W -= learning_rate * dL_dW\n",
        "  b -= learning_rate * dL_db.flatten()  # 将(1,1)转为(1,)\n",
        "\n",
        "# 执行一次反向传播\n",
        "backward(x, y_true, W, b)\n",
        "print(\"更新后的W:\", W)  # 输出：[[0.516], [-0.255]]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9fJCwTFKpSqs",
        "outputId": "fd08b712-6eb0-4ed0-c375-b4933418dee7"
      },
      "execution_count": 57,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "更新后的W: [[ 0.515]\n",
            " [-0.27 ]]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "4.1 数据准备"
      ],
      "metadata": {
        "id": "bP0SBpWumfA1"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from tensorflow.keras.datasets import mnist\n",
        "\n",
        "# 加载数据\n",
        "(X_train, y_train), (X_test, y_test) = mnist.load_data()\n",
        "\n",
        "# 预处理\n",
        "X_train = X_train.reshape(-1, 784) / 255.0  # 展平并归一化\n",
        "X_test = X_test.reshape(-1, 784) / 255.0\n",
        "\n",
        "# 将标签转为one-hot编码\n",
        "def to_onehot(y):\n",
        "  return np.eye(10)[y]\n",
        "\n",
        "y_train = to_onehot(y_train)\n",
        "y_test = to_onehot(y_test)\n"
      ],
      "metadata": {
        "id": "HEbTY3wVjB4N"
      },
      "execution_count": 58,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "4.2 网络实现"
      ],
      "metadata": {
        "id": "mRm4IKrYmmhb"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class NeuralNetwork:\n",
        "  def __init__(self):\n",
        "    # 初始化参数（使用更合理的初始化方法）\n",
        "    self.W1 = np.random.randn(784, 128) * np.sqrt(2./784)\n",
        "    self.b1 = np.zeros(128)\n",
        "    self.W2 = np.random.randn(128, 10) * np.sqrt(2./128)\n",
        "    self.b2 = np.zeros(10)\n",
        "\n",
        "  def relu(self, x):\n",
        "    return np.maximum(0, x)\n",
        "\n",
        "  def softmax(self, x):\n",
        "    exps = np.exp(x - np.max(x, axis=1, keepdims=True))\n",
        "    return exps / np.sum(exps, axis=1, keepdims=True)\n",
        "\n",
        "  def forward(self, x):\n",
        "    self.z1 = np.dot(x, self.W1) + self.b1\n",
        "    self.a1 = self.relu(self.z1)\n",
        "    self.z2 = np.dot(self.a1, self.W2) + self.b2\n",
        "    return self.softmax(self.z2)\n",
        "\n",
        "  def backward(self, x, y, lr=0.01):\n",
        "    m = x.shape[0]  # 批大小\n",
        "\n",
        "    # 输出层梯度\n",
        "    dL_dz2 = self.forward(x) - y\n",
        "\n",
        "    # 隐藏层梯度\n",
        "    dL_da1 = np.dot(dL_dz2, self.W2.T)\n",
        "    dL_dz1 = dL_da1 * (self.a1 > 0)  # ReLU导数\n",
        "\n",
        "    # 参数梯度\n",
        "    dL_dW2 = np.dot(self.a1.T, dL_dz2) / m\n",
        "    dL_db2 = np.sum(dL_dz2, axis=0) / m\n",
        "    dL_dW1 = np.dot(x.T, dL_dz1) / m\n",
        "    dL_db1 = np.sum(dL_dz1, axis=0) / m\n",
        "\n",
        "    # 更新参数\n",
        "    self.W2 -= lr * dL_dW2\n",
        "    self.b2 -= lr * dL_db2\n",
        "    self.W1 -= lr * dL_dW1\n",
        "    self.b1 -= lr * dL_db1"
      ],
      "metadata": {
        "id": "MFcAMvlQmqAU"
      },
      "execution_count": 59,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "4.3 训练过程"
      ],
      "metadata": {
        "id": "f0-pJO2Sm3UM"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nn = NeuralNetwork()\n",
        "\n",
        "for epoch in range(20):\n",
        "  # 小批量训练\n",
        "  for i in range(0, len(X_train), 64):\n",
        "    X_batch = X_train[i:i+64]\n",
        "    y_batch = y_train[i:i+64]\n",
        "    nn.backward(X_batch, y_batch)\n",
        "\n",
        "  # 评估\n",
        "  pred = np.argmax(nn.forward(X_test), axis=1)\n",
        "  acc = np.mean(pred == np.argmax(y_test, axis=1))\n",
        "  print(f\"Epoch {epoch}, 测试准确率: {acc:.3f}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PNgwikuXm4Az",
        "outputId": "c68e6cf2-55e8-4434-b845-9aed0c21c0ea"
      },
      "execution_count": 60,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 0, 测试准确率: 0.884\n",
            "Epoch 1, 测试准确率: 0.903\n",
            "Epoch 2, 测试准确率: 0.911\n",
            "Epoch 3, 测试准确率: 0.918\n",
            "Epoch 4, 测试准确率: 0.922\n",
            "Epoch 5, 测试准确率: 0.926\n",
            "Epoch 6, 测试准确率: 0.929\n",
            "Epoch 7, 测试准确率: 0.932\n",
            "Epoch 8, 测试准确率: 0.935\n",
            "Epoch 9, 测试准确率: 0.938\n",
            "Epoch 10, 测试准确率: 0.940\n",
            "Epoch 11, 测试准确率: 0.943\n",
            "Epoch 12, 测试准确率: 0.944\n",
            "Epoch 13, 测试准确率: 0.946\n",
            "Epoch 14, 测试准确率: 0.947\n",
            "Epoch 15, 测试准确率: 0.949\n",
            "Epoch 16, 测试准确率: 0.950\n",
            "Epoch 17, 测试准确率: 0.950\n",
            "Epoch 18, 测试准确率: 0.951\n",
            "Epoch 19, 测试准确率: 0.953\n"
          ]
        }
      ]
    }
  ]
}